/*************************************************************************
    > File Name: 3.epoll_server.c
    > Author: Ykk
    > Mail: 3393579535@qq.com 
    > Created Time: 2023年05月27日 星期六 10时29分30秒
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/epoll.h>
#include<fcntl.h>
#include"network_utils.h"

#define IP "192.168.152.129"
#define PORT 8888
#define SIZE 1024

int main(int argc,char *argv[])
{
	//创建套接字 绑定
	int lfd = tcp4bind(PORT,IP);
	//监听
	Listen(lfd,128);
	//创建树
	int epfd = epoll_create(1);
	//将lfd上树
	struct epoll_event ev,evs[SIZE];
	ev.data.fd = lfd;
	ev.events = EPOLLIN;
	epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&ev);
    
	//while监听
	while(1)
	{
		int nread = epoll_wait(epfd,evs,SIZE,-1);
		if(nread < 0)
		{
			perror("epoll_wait");
			break;
		}
		else if(nread == 0)
		{
			continue;
		}
		else//有文件描述符变化
		{	
			for(int i = 0;i < nread;i++)
			{
				//判断lfd变化，并且是读事件变化
				if(evs[i].data.fd == lfd && evs[i].events&EPOLLIN)
				{
					struct sockaddr_in cliaddr;
					char ip[16] = "";
					socklen_t len = sizeof(cliaddr);
					int cfd = Accept(lfd,(struct sockaddr*)&cliaddr,&len);
					inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,ip,16);
					printf("new client %s  %d\n",ip,ntohs(cliaddr.sin_port));
					//设置cfd为非阻塞
					int flags = fcntl(cfd,F_GETFL);//获取cfd的标志位
					flags |= O_NONBLOCK;
					fcntl(cfd,F_SETFL,flags);
					//将cfd上树
					ev.data.fd = cfd; 
					ev.events = EPOLLIN | EPOLLET;
					epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&ev);
				
				}
				else if(evs[i].events & EPOLLIN)//cfd变化，而且是读事件变化
				{
					while(1)
					{
						char buf[4] = "";
						//如果读一个缓冲区,缓冲区没有数据，如果是带阻塞的，就阻塞等待
						//如果是非阻塞,返回值为-1，并且会将errno值设置为EAGAIN
						int n = read(evs[i].data.fd,buf,sizeof(buf));
						if(n < 0)
						{
							//如果缓冲区都干净了，跳出while循环继续监听
							if(errno == EAGAIN)
							{
								break;
							}
							//普通错误
							perror("read");
							epoll_ctl(epfd,EPOLL_CTL_DEL,evs[i].data.fd,&evs[i]);
							close(evs[i].data.fd);//将cfd关闭
							break;
						}
						else if(n == 0)//客户端关闭
						{
							printf("client   close\n");
							epoll_ctl(epfd,EPOLL_CTL_DEL,evs[i].data.fd,&evs[i]);//下树
							close(evs[i].data.fd);//将cfd关闭
							break;
						}
						else
						{
							char serverbuf[4+10]=" server==>";;
							printf("%s\n",buf);
							strcat(serverbuf,buf);
							write(evs[i].data.fd,serverbuf,n+10);
						}
					}
				}
			}
		}
	}
	return 0;
} 
